/*
 * Serum
 *
 * @license      GNU Lesser General Public Licence see LICENCE-LGPL file or http://www.gnu.org/licenses/lgpl.html
 */

Serum.Grid.Module.List = Ext.extend(Ext.grid.GridPanel, {

    /**
     * Constructor
     *
     * @param       {Ext.Component}     viewer
     * @param       {Object}            config
     */
    constructor: function(viewer, config) {
        this.viewer         = viewer;
        this.storeLoaded    = false;

        if (this.pageSize === null) {
            this.pageSize = Serum.Preferences.get().getValue('ELEMENTS_PER_PAGE');
        }

        this.store      = this._getStore();
        this.columns    = this.getColumns();
        this.toolbar    = this.getToolbarButtons();
        
        if (!this.enableDragAndDrop) {
            this.pagingBar  = this.getPagingbar();
        }
        this.listType   = 'normal';

        Serum.Grid.Module.List.superclass.constructor.call(this, Ext.apply({
            id:                 'element-grid',
            loadMask:           {msg: __('base~list_loading')},
            autoExpandColumn:   this.getAutoExpandColumn(),
            border:             false,
            tbar:               this.toolbar,
            sm:                 this.selectionModel(),
            stripeRows:         true,
            enableDragDrop:     (this.enableDragAndDrop),
            ddGroup:            (this.enableDragAndDrop) ? 'DDGroup' : null,

            viewConfig: {
                forceFit:       false,
                enableRowBody:  true,
                showPreview:    false,

                getRowClass: function(record, rowIndex, p, store) {
                    if (this.showPreview) {
                        p.body = '<p>'+ record.data.id +'</p>';
                        return 'x-grid3-row-expanded';
                    }
                    return 'x-grid3-row-collapsed';
                }
            },

            bbar: this.pagingBar
        }, config));

        // Rows style
        this.getView().getRowClass = function(record, index){
            var cssClass    = '';

            if (record.data.type == 'parent' && !this.enableDragAndDrop) {
                cssClass    += 'parent-element ';
            }

            if (record.data.status == 1) {
                cssClass    += 'disabled-element';
            } else {
                cssClass    += 'enabled-element';
            }

            return cssClass;
        };

        // Events
        this.on('rowcontextmenu',   this.onContextClick, this);
        this.on('rowdblclick',      this.onOpenElement, this);
        this.on('keydown',          function(e) { if (e.keyCode == 13) this.onOpenElement(e); }, this);

        if (this.enableDragAndDrop) {

            this.defaultSort = {sort: 'lft', dir: 'asc'};

            this.on('render', function() {
                var grid = this;

                new Ext.dd.DropTarget(grid.container, {
                    ddGroup:    'DDGroup',
                    copy:       false,
                    notifyDrop: function(dd, e, data) {
                        var ds = grid.store;

                        var sm      = grid.getSelectionModel();
                        var rows    = sm.getSelections();

                        if (dd.getDragData(e)) {
                            var targetData  = dd.getDragData(e).selections[0].data;
                            var parent      = targetData._parent || null;
                            var ids         = [];
                            var model       = null;

                            parent          = (parent === null) ? targetData.id.split('-')[1] : parent.split('-')[1];

                            for (var i = 0; i < rows.length; i++) {
                                if (rows[i].data.type == 'model') {
                                    var _data = rows[i].data.id.split('-');
                                    ids.push(_data[1]);

                                    if (model === null)  {
                                        model = _data[0];
                                    }
                                }
                            }

                            if (ids.length > 0) {
                                Serum.Ajax.request({
                                    scope:      grid,
                                    params:     {
                                                    method:     Serum.Selector.get().method({ module: Serum.Selector.get().module, controller: 'Index', action: 'switchElements' }),
                                                    requestId:  Serum.Helper.Request.id(),
                                                    ids:        ids.implode('-'),
                                                    target:     parent,
                                                    model:      model
                                                },
                                    onSuccess:  function() {
                                                    ds.load();
                                                }
                                });
                            }
                        }
                    }
                });
            }, this);
        }

        this.loadSerumEvents();
    },

    /**
     * Loads Serum global events
     */
    loadSerumEvents: function() {
        Serum.App.get().eventListener.on('refreshlist',     this.onRefreshList,     this);
    },

    /**
     * Unloads Serum global events
     */
    unloadSerumEvents: function() {
        Serum.App.get().eventListener.un('refreshlist',     this.onRefreshList,     this);
    },

    /**
     * Data stored in each row in the grid, not displayed
     * Mandatory fields : id, status, iconCls, title, nested, type
     */
    fields: ['id', 'status', 'iconCls', 'title', 'nested', 'type'],

    /**
     * Extra rows
     */
    extraFields: [],

    /**
     * Drag and drop
     */
    enableDragAndDrop: false,

    /**
     * Default element's sort
     *  - sort :
     *      'field1'        : sorting parent and model by field1
     *      OR
     *      'field1|field2' : sorting model by field1, parent by fields2
     *  - dir :
     *      'dir1'        : sorting parent and model by dir1
     *      OR
     *      'dir1|dir2' : sorting model by dir1, parent by dir2
     */
    defaultSort: {sort: 'id', dir: 'ASC'},

    /**
     * Default page size
     *
     * @cfg     {Number}
     */
    pageSize: null,

    /**
     * Gets fields
     *
     * @param       {Mixed}
     */
    getFields: function() {
        var _fields = this.fields;
        for(var i = 0; i < this.extraFields.length; i++) {
            _fields.push(this.extraFields[i]);
        }

        return _fields;
    },

    /**
     * Gets store
     *
     * @param       {Ext.Component}
     */
    _getStore: function() {
        var store = new Ext.data.JsonStore({
                            root:           'result',
                            totalProperty:  'count',
                            id:             'id',

                            fields:         this.getFields(),

                            url:            Serum.Selector.get().requestUrl(),
                            remoteSort:     true,

                             listeners: {
                                 loadexception: function() {
                                     Serum.Exception.Handler.process('unknown');
                                 }
                             }
                        });

        store.setDefaultSort(this.defaultSort.sort, this.defaultSort.dir);

        return store;
    },

    /**
     * Returns columns list to display
     *
     * @return      {Array}
     */
    getColumns: function() {
        return [this.selectionModel(), {
            id:         'icon',
            header:     __('base~list_column_icon'),
            dataIndex:  'iconCls',
            renderer:   this.iconRenderer,
            width:      20
        }, {
            id:         'title',
            header:     __('base~list_column_title'),
            dataIndex:  'title',
            sortable:   false
        }];
    },

    /**
     * @return  {String}
     */
    getAutoExpandColumn: function() {
        return 'title';
    },

    /**
     *
     * @param   {String}    value
     * @param   {Object}    cel
     */
    iconRenderer: function(value, cel) {
        cel.css = value;
    },

    /**
     * Returns list selection model
     *
     * @return  {Ext.grid.RowSelectionModel}
     */
    selectionModel: function() {
        return new Ext.grid.CheckboxSelectionModel();
    },

    /**
     * Returns the list of buttons of the toolbar
     *
     * @return  {Array}
     */
    getToolbarButtons: function() {
        var toolbar = new Array();

        if ((typeof Serum.Selector.get().getParams['parentRoot'] !== 'undefined') ||
            (typeof Serum.Selector.get().getParams['modelRoot'] !== 'undefined')) {
            toolbar.push(new Serum.Grid.Module.Toolbar.LevelUpButton(this));
            toolbar.push('-');
        }

        toolbar.push(new Serum.Grid.Module.Toolbar.AddButton(this));
        toolbar.push(new Serum.Grid.Module.Toolbar.AddParentButton(this));
        toolbar.push('-');
        toolbar.push(new Serum.Grid.Module.Toolbar.EnableButton(this));
        toolbar.push(new Serum.Grid.Module.Toolbar.DisableButton(this));
        toolbar.push(new Serum.Grid.Module.Toolbar.DeleteButton(this));
        toolbar.push('-');
        toolbar.push(new Serum.Grid.Module.Toolbar.SearchButton(this));

        return toolbar;
    },

    /**
     * Refreshs the toolbar depending on the module
     */
    refreshToolbar: function() {
        // Removes all elements
        var i = 0;

        for (i = 0 ; i < this.getTopToolbar().items.getCount() ; i++) {
            this.getTopToolbar().items.get(i).destroy();
        }

        var buttons = this.getToolbarButtons();

        for (i = 0 ; i < buttons.length ; i++) {
            if (Serum.Preferences.get().getValue('DISPLAY_PICTO_TEXT') == 1) {
                if (typeof buttons[i].tooltip !== 'undefined' && typeof buttons[i].text === 'undefined') {
                    buttons[i].text = buttons[i].tooltip.title;
                }
            }

            this.getTopToolbar().add(buttons[i]);
        }
    },

    /**
     * Returns the pagingbar of the list
     *
     * @return  {Ext.PagingToolbar}
     */
    getPagingbar: function() {
        var pagingbar = new Ext.PagingToolbar({
            pageSize:       this.pageSize,
            store:          this.store,
            displayInfo:    true,
            displayMsg:     __('base~list_displayMsg'),
            emptyMsg:       __('base~list_emptyMsg'),
            beforePageText: __('base~list_beforePageText'),
            afterPageText:  __('base~list_afterPageText'),
            firstText:      __('base~list_firstText'),
            lastText:       __('base~list_lastText'),
            nextText:       __('base~list_nextText'),
            prevText:       __('base~list_prevText'),
            refreshText:    __('base~list_refreshText')
        });

        return pagingbar;
    },

    /**
     * @return  {String}
     */
    getTitle: function() {
        return __(Serum.Selector.get().module.toLowerCase() + '~list_title', 'base~list_title');
    },

    /**
     * Return the allowed context menu
     *
     * @return  {Array}
     */
    getAllowedContextMenu: function() {
        if (this.enableDragAndDrop) {
            return ['edit', 'enable', 'disable', 'delete', 'refresh'];
        }

        return ['open', 'addin', 'edit', 'enable', 'disable', 'delete', 'refresh'];
    },

    /**
     * Returns the context menu in the list
     *
     * @return  {Ext.menu.Menu}
     */
    contextMenu: function(grid) {
        this._contextMenu = new Ext.menu.Menu({
            id: 'grid-ctx'
        });

        // Boolean if displaying enable / disable menus
        var enableMenu      = false;
        var disableMenu     = false;
        var isContainer     = false;
        var allowedMenus    = this.getAllowedContextMenu();

        // Gets selected elements
        var selection = this.getSelectionModel().getSelections();

        // Loops on elements
        for (i = 0; i < selection.length ; i++) {
            if (selection[i].data.status == 2) {
                disableMenu = true;
            } else if (selection[i].data.status == 1) {
                enableMenu = true;
            }

            if (selection[i].data.iconCls == 'container') {
                isContainer  = true;
            }
        }

        // Menu : Dir open, add in
        if (selection.length == 1 && isContainer) {
            if (allowedMenus.contains('open')) {
                this._contextMenu.add(new Serum.Grid.Module.ContextMenu.OpenButton(this));
            }
            if (allowedMenus.contains('addin')) {
                this._contextMenu.add(new Serum.Grid.Module.ContextMenu.AddInButton(this));
            }
        }

        // Menu : modification
        if (selection.length == 1) {
            if (allowedMenus.contains('edit')) {
                this._contextMenu.add(new Serum.Grid.Module.ContextMenu.EditButton(grid));
            }
        }

        // Menu : enable / disable, delete
        if (selection.length > 0) {
            if (enableMenu) {
                if (allowedMenus.contains('enable')) {
                    this._contextMenu.add(new Serum.Grid.Module.ContextMenu.EnableButton(grid));
                }
            }

            if (disableMenu) {
                if (allowedMenus.contains('disable')) {
                    this._contextMenu.add(new Serum.Grid.Module.ContextMenu.DisableButton(grid));
                }
            }

            if (allowedMenus.contains('delete')) {
                this._contextMenu.add(new Serum.Grid.Module.ContextMenu.DeleteButton(grid));
            }
        }

        // Separator
        if (this._contextMenu.items.getCount() > 0) {
            this._contextMenu.add('-');
        }

        // Menu : refresh
        if (allowedMenus.contains('refresh')) {
            this._contextMenu.add(new Serum.Grid.Module.ContextMenu.RefreshButton(this));
        }

        return this._contextMenu;
    },

    /**
     * Handler for context click event
     */
    onContextClick : function(grid, index, e) {

        if (! this.selModel.isSelected(index)) {
            // if the row right clicked on isn't selected already, select it
            // and fire the event
            this.selModel.selectRow(index);
            this.fireEvent('rowclick', this, index, e);
        }

        var menu = this.contextMenu(grid);
        menu.on('hide', this.onContextHide, this);

        e.stopEvent();

        if (this.ctxRow) {
            Ext.fly(this.ctxRow).removeClass('x-node-ctx');
            this.ctxRow = null;
        }

        this.ctxRow     = this.view.getRow(index);
        this.ctxRecord  = this.store.getAt(index);

        Ext.fly(this.ctxRow).addClass('x-node-ctx');

        menu.showAt(e.getXY());
    },

    onContextHide : function(){
        if (this.ctxRow) {
            Ext.fly(this.ctxRow).removeClass('x-node-ctx');
            this.ctxRow = null;
        }
    },

    /**
     * Fired when an element is opened
     */
    onOpenElement: function() {
        if (this.getSelectionModel().getSelected().data.type == 'parent') {
            this.onViewContentElement();
        } else {
            this.onEditElement();
        }
    },

    /**
     * Displays the element's content
     */
    onViewContentElement: function() {
        var splittedId  = this.getSelectionModel().getSelected().data.id.split('-');
        var id          = splittedId[1];

        if (this.getSelectionModel().getSelected().data.type == 'parent') {
            Serum.Selector.get().set({  action: 'index',
                                            parentRoot: id
                                        }, false);
        } else if (this.getSelectionModel().getSelected().data.type == 'model') {
            Serum.Selector.get().set({  action: 'index',
                                            modelRoot: id
                                        }, false);
        }
    },

    /**
     * Fired when the list is refreshed
     */
    onRefreshList: function(params) {

        var _sentParams     = {};
        var value           = null;
        var operator        = '=';
        var params          = params || {};
        var search          = params.search || {};

        for (var param in search) {
            if (typeof search[param] === 'function') {
                return;
            }

            if (search[param] !== '') {
                value       = null;
                operator    = '=';

                if (typeof search[param] === 'object') {
                    if (typeof search[param]['value'] !== 'undefined') {
                        value = search[param]['value'];
                    }

                    if (typeof search[param]['operator'] !== 'undefined') {
                        operator = search[param]['operator'];
                    }
                } else {
                    value = search[param];
                }

                _sentParams[param]      = operator + '__' + value;
                _sentParams['search']   = true;
            }
            _sentParams['search'] = true;
        }

        this.store.baseParams = {
                                    method:         Serum.Selector.get().method({action: 'index'}),
                                    requestId:      Serum.Helper.Request.id(),
                                    modelRoot:      Serum.Selector.get().getParams['modelRoot'],
                                    parentRoot:     Serum.Selector.get().getParams['parentRoot'],
                                    //start:          0,
                                    limit:          this.pageSize,
                                    listType:       this.listType
                                };

        Ext.apply(this.store.baseParams, _sentParams, {});

        if (!this.storeLoaded) {
            this.store.load();
            this.storeLoaded = true;

        } else {
            this.store.reload();
        }
    },

    /**
     * Fired when the action is changed
     */
    onActionChanged: function() {
        if (!this.storeLoaded || this.isListAction()) {
            // Refresh toolbar
            this.refreshToolbar();

            // Refresh the list
            this.onRefreshList();
        }
    },

    /**
     * Returns true if current action is a list action
     *
     * @return      {Booleann}
     */
    isListAction: function() {
        return ['index'].contains(Serum.Selector.get().action);
    },

    /**
     * Fired when creating  a new element
     */
    onNewElement: function() {
        Serum.Selector.get().set({ action: 'add' }, false);
    },

    /**
     * Fired when creating  a new element in a parent
     */
    onNewInElement: function() {
        var params      = {};
        params.action   = 'add';

        if (this.getSelectionModel().getSelected().data.type == 'parent') {
            params.parentRoot   = this.getSelectionModel().getSelected().data.id;
        } else {
            params.modelRoot    = this.getSelectionModel().getSelected().data.id;
        }

        Serum.Selector.get().set(params, false);
    },

    /**
     * Fired when creating a new parent element
     */
    onNewParentElement: function() {
        Serum.Selector.get().set({  action: 'addParent'}, false);
    },

    /**
     * Fired when an element is edited
     */
    onEditElement: function() {
        var params      = {};
        var splittedId  = this.getSelectionModel().getSelected().data.id.split('-');
        params.id       = splittedId[1];

        if (this.getSelectionModel().getSelected().data.type == 'parent') {
            params.action    = 'editParent';
        } else {
            params.action    = 'edit';
        }

        Serum.Selector.get().set(params, false);
    },

    /**
     * Fired when creating  a new element
     */
    onSearchElement: function() {
        Serum.Selector.get().set({ action: 'advancedSearch' });
    },

    /**
     * Fired when an element is processed
     */
    onProcessElement: function(event) {
        var objectsList     = this.getSelectionModel().getSelections();
        var listeModelId    = [];
        var listeParentId   = [];

        for (id = 0 ; id < objectsList.length ; id++) {
            var splittedId = objectsList[id].data.id.split('-');

            if (objectsList[id].data.type == 'parent') {
                listeParentId.push(splittedId[1]);
            } else {
                listeModelId.push(splittedId[1]);
            }
        }

        if (listeModelId.length > 0) {
            Serum.App.get().eventListener.fireEvent(event + 'element', listeModelId.implode('-'));
        }
        if (listeParentId.length > 0) {
            Serum.App.get().eventListener.fireEvent(event + 'parentelement', listeParentId.implode('-'));
        }
    },

    /**
     * Fired when an element is enabled
     */
    onEnableElement: function() {
        this.onProcessElement('enable');
    },

    /**
     * Fired when an element is disabled
     */
    onDisableElement: function() {
        this.onProcessElement('disable');
    },

    /**
     * Fired when an element is deleted
     */
    onDeleteElement: function() {
        this.onProcessElement('delete');
    },

    /**
     * Fired when go one level up
     * Search the element above the current
     * Redirect to the new list
     */
    onLevelUp: function() {
        Serum.Ajax.request({
            scope:       this,
            params:      {
                            method:         Serum.Selector.get().method({
                                                                            module:         Serum.Selector.get().module,
                                                                            controller:     'Index',
                                                                            action:         'getElementAboveId'
                                                                        }),
                            parentRoot:     Serum.Selector.get().getParams['parentRoot'],
                            modelRoot:      Serum.Selector.get().getParams['modelRoot'],
                            requestId:      Serum.Helper.Request.id()
                        },
            onSuccess:  function(response) {
                            var jsonResponse = Ext.util.JSON.decode(response.responseText);
                            Serum.Selector.get().set({
                                                        action:         'index',
                                                        parentRoot:     jsonResponse.result['parentId'],
                                                        modelRoot:      jsonResponse.result['modelId']
                                                    });
                       }
        });
    }
});